//
//  Localization.cpp
//  client
//
//  Created by DuanHongbo on 15/12/22.
//
//

#include "Localization.h"
#include "sqlite3.h"
#include "cocos2d.h"
#include "tolua_fix.h"
#include "rapidjson/document.h"
USING_NS_CC;

static Localization* _instance = nullptr;

static sqlite3 *_db=nullptr;
static sqlite3_stmt *_stmt_select=nullptr;


Localization* Localization::getInstance()
{
    if(!_instance){
        _instance = new Localization();
    }
    return _instance;
}

void Localization::destoryInstance()
{
    if(_instance){
        _instance->destory();
        delete _instance;
        _instance=nullptr;
    }
}

void Localization::initWithSqlite(const char* filePath){
    destory();
    
    clearCaches();
    
    std::string fullpath;
    fullpath =  cocos2d::FileUtils::getInstance()->fullPathForFilename(filePath);
    cocos2d::log("===>Localization db path: %s",fullpath.c_str());
    int ret = sqlite3_open(fullpath.c_str(), &_db);

    if( ret != SQLITE_OK ) {
        cocos2d::log("====>Localization initializing fail %d\n",ret);
        // report error
        _db=nullptr;
    }
    
    
    CCASSERT(_db, "db is null");
    
    if(_stmt_select){
        sqlite3_finalize(_stmt_select);
        _stmt_select=nullptr;
    }
    std::string sql_select = cocos2d::StringUtils::format("SELECT %s FROM string WHERE ID=?;",_language.c_str());
    ret = sqlite3_prepare_v2(_db, sql_select.c_str(), -1, &_stmt_select, nullptr);
    if(ret!=SQLITE_OK){
        cocos2d::log("====>Localization Error sqlite3_prepare_v2 fail %d \n",ret);
        _stmt_select=nullptr;
    }
}

void Localization::initWithJson(const std::string& content)
{
    rapidjson::Document doc;
    doc.Parse<0>(content.c_str());
    if (doc.HasParseError())
    {
        CCLOG("Localization - initWithJson param is not json format:%d", doc.GetParseError());
        return;
    }
    
    clearCaches();
    
    int count = doc.MemberCount();
    _cachedMap.reserve(count);
    for (rapidjson::Value::ConstMemberIterator it = doc.MemberBegin();it != doc.MemberEnd(); ++it) {
        _cachedMap.emplace(it->name.GetString(),it->value.GetString());
//        std::string key = it->name.GetString();
//        auto lit = it->value.FindMember(_language.c_str());
//        if(lit!=it->value.MemberEnd()){
//            const rapidjson::Value& value = lit->value;
//            if (value.IsString()){
//                _cachedMap.emplace(key,value.GetString());
//            }
//        }
    }
}

void Localization::destory()
{
    if(_stmt_select){
        sqlite3_finalize(_stmt_select);
        _stmt_select=nullptr;
    }
    if(_db){
        sqlite3_close(_db);
        _db=nullptr;
    }
}

void Localization::clearCaches()
{
    _cachedMap.clear();
}

void Localization::setLanguage(const char* lg)
{
    _language = lg;
    assert(!_language.empty());
}

const std::string& Localization::getStr(const std::string& key,const std::string& def)
{
    if(key.empty()){
        return key;
    }
    
    StringDict::iterator it = _cachedMap.find(key);
    if(it!=_cachedMap.end()){
        return it->second;
    }
    
    std::string ret(key);
    
    if(_stmt_select){
        int ok = sqlite3_reset(_stmt_select);
        ok |= sqlite3_bind_text(_stmt_select, 1, key.c_str(), -1, SQLITE_TRANSIENT);
        ok |= sqlite3_step(_stmt_select);
        const unsigned char *text = sqlite3_column_text(_stmt_select, 0);
        if (text)
            ret = (const char*)text;
        
        if( ok != SQLITE_OK && ok != SQLITE_DONE && ok != SQLITE_ROW){
            printf("Error in localStorage.getItem()\n");
            ret = def.empty()?key:def;
        }
    }
    
    _cachedMap[key]=ret;
    
    return _cachedMap[key];
}

const std::string& Localization::getStr(const std::string& key)
{
    return getStr(key, key);
}

// 获取 当前 包的 默认语言环境
const std::string Localization::getAppDefaultLang(){
    std::string language = Configuration::getInstance()->getValue("LANGUAGE",Value("CHS")).asString();
    return language;
}

// 获取 当前用户选择的 语言包
const std::string Localization::getUserSelectLang(){
    std::string lang = UserDefault::getInstance()->getStringForKey("LANGUAGE", "");
    if(lang == ""){
        lang = getAppDefaultLang();
    }
    return lang;
}

//

static int lua_L10N_getStr(lua_State *L){
    int argc = lua_gettop(L);
    if(argc<=0){
        luaL_error(L, "function of lua_GetL10NString has wrong number of arguments: %d, was expecting %d\n", argc, 1);
        lua_pushnil(L);
        return 1;
    }
    
    
    const char* key = tolua_tostring(L, 1,NULL);
    const char* def = "";
    
    if(argc>1){
        def = tolua_tostring(L, 2,"");
    }
    
    if(!key){
        lua_pushstring(L, def);
        return 1;
    }
    
    const std::string& ret = Localization::getInstance()->getStr(key,def);
    lua_pushstring(L, ret.c_str());
    return 1;
}

static int lua_L10N_setLanguage(lua_State *L){
    int argc = lua_gettop(L);
    if(argc!=1){
        luaL_error(L, "function of lua_L10N_setLanguage has wrong number of arguments: %d, was expecting %d\n", argc, 1);
        return 0;
    }
    const char* ln = tolua_tostring(L, 1, "");
    if(!ln){
        return 0;
    }
    
    Localization::getInstance()->setLanguage(ln);

    return 0;
}

static int lua_L10N_clearCaches(lua_State *L){
    Localization::getInstance()->clearCaches();
    return 0;
}

static int lua_L10N_getUserSelectLang(lua_State *L){
    lua_pushstring(L, Localization::getInstance()->getUserSelectLang().c_str());
    return 1;
}

static int lua_L10N_getAppDefaultLang(lua_State *L){
    lua_pushstring(L, Localization::getInstance()->getAppDefaultLang().c_str());
    return 1;
}

void regist_L10N_functions(lua_State* L)
{
    tolua_open(L);
    tolua_module(L,"L10N",0);
    tolua_beginmodule(L,"L10N");
    tolua_function(L,"getString",lua_L10N_getStr);
    tolua_function(L,"setLanguage",lua_L10N_setLanguage);
    tolua_function(L,"clearCaches",lua_L10N_clearCaches);
    tolua_function(L,"getUserSelectLang",lua_L10N_getUserSelectLang);
    tolua_function(L,"getAppDefaultLang",lua_L10N_getAppDefaultLang);
    tolua_endmodule(L);
}
